import { ArrUtils } from "../utils/ArrUtils";

const levelData = {
    current: 0,
    levels:[
        [1, 30, 3],
        [2, 50, 5],
        [3, 100, 5]
    ]
}

const enemyData = {
    positions:[
        [0, 0],
        [0, 16*19],
        [16*29, 0],
        [16*29, 16*19]
    ],
    dirs:[
        'down',
        'up',
        'left',
        'up'
    ]
}

export class PlayScene extends Phaser.Scene {
    
    private levelInfo: any;
    private enemyNum: number;
    private score: number;

    private isOver: boolean;

    private enemies: Phaser.GameObjects.Group;
    private bullets: Phaser.GameObjects.Group;

    private enemyBullets: Phaser.GameObjects.Group;

    private bores: Phaser.GameObjects.Group;
    private spaceKey: Phaser.Input.Keyboard.Key;
    private leftKey: Phaser.Input.Keyboard.Key;
    private rightKey: Phaser.Input.Keyboard.Key;
    private upKey: Phaser.Input.Keyboard.Key;
    private downKey: Phaser.Input.Keyboard.Key;

    private player: Phaser.Types.Physics.Arcade.SpriteWithDynamicBody;
    
    private map: Phaser.Tilemaps.Tilemap;
    private layer: Phaser.Tilemaps.TilemapLayer;
    
    private speed: number;

    private enemyNextTime: number;
    
    constructor() {
        super({ key: 'PlayScene' });
    }
    
    create(): void {
        /* const soundStart = this.sound.add('sound-start');
        soundStart.play(); */

        this.init();
        this.speed = 20; this.enemyNextTime = 0;
        
        this.map = this.make.tilemap({ key: 'levels' })
            ;
        const tileset = this.map.addTilesetImage('tile');
        
        this.layer = this.map.createLayer('level-'+this.levelInfo[0], tileset, 0, 0)
            .setCollisionBetween(0, 4, true)
            ;

        // this.seeTileIndex();
        
        // just set collision between the player and the tiles, not for the enemies. 
        // this.layer.setCollisionByExclusion([4, 5, 6, 7, 8, 9], true);
        // this.physics.world.enable(this.layer);
        
        this.enemies = this.add.group();
        console.log( 'see type enemy group', typeof this.enemies);

        // init enemies
        for(let i = 0; i < 8; i++){
            this.initEnemy(i);
        }
        // 60 * 8 / 40 * 8
        this.player = this.physics.add.sprite( 26*8, 38*8, 'tank', 0);
        this.cameras.main.setBounds(0, 0, this.map.widthInPixels, this.map.heightInPixels);
        
        this.initPlayerAnimations();

        
        this.spaceKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
        this.leftKey  = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
        this.rightKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);    
        this.upKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
        this.downKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);

        this.bullets = this.add.group();
        for(let i = 0; i < 2; i++){
            this.bullets.create(0, 0, 'bullet');
        }

        this.enemyBullets = this.add.group();

        this.bores = this.add.group();

        this.bores.create(0, 0, 'bore', 0);

        this.add.text(0, 0, 'Score: '+this.score, {fontSize: '16px', color: '#fff'});
        this.addCollisions();
    }

    seeTileIndex(): void {
        const tileWidth = this.layer.width;
        const tileHeight = this.layer.height;

        for (let y = 1; y < tileHeight; y++) {
            for (let x = 1; x < tileWidth; x++) {
                // 获取当前tile的索引
                const tileIndex = this.map.getTileAt(x, y, false, this.layer);
                // 打印出tile的位置和索引
                console.log(`Tile at (${x}, ${y}) has index: ${tileIndex}`);
            }
        }
    }

    update(time: number, delta: number): void {
        this.layerBoundsCheckWithPlayer();
        
        if(!this.isOver){
            if(this.downKey.isDown){
                this.player.play('down', true);
                this.player.setVelocityY(this.speed);
            } else if(this.upKey.isDown){
                this.player.play('up', true);
                this.player.setVelocityY(-this.speed);
            } else if(this.leftKey.isDown){
                this.player.play('left', true);
                this.player.setVelocityX(-this.speed);
            } else if(this.rightKey.isDown){
                this.player.play('right', true);
                this.player.setVelocityX(this.speed);
            } else {
                this.player.setVelocity(0, 0);
            }

            if(time > this.enemyNextTime){
                this.enemyMove(time);
                this.enemyNextTime = time + (Math.random() * 1100 + 1000);
            }
        }
    }
    
    init(): void {
        this.levelInfo = levelData.levels[levelData.current];
        this.enemyNum = this.levelInfo[1];
        // this.facing = 0;
        this.score = this.enemyNum;

        this.isOver = false;
    }
    
    private addCollisions(): void {
        this.physics.add.collider(this.player, this.layer);
        this.physics.add.collider(this.enemies, this.layer);
        this.physics.add.collider(this.enemies, this.enemies);
    }
    
    private enemyMove(time: number): void {
        this.enemies.getChildren().forEach( (enemy: any) => {
            enemy.body.setVelocity(0, 0);
            
            let ds = ['up', 'left', 'down', 'right'];
            let {x, y} = enemy;
            
            if( (x-1) < 0 ){
                ArrUtils.remove(ds, 'left');
            }
            if( (y-1) < 0){
                ArrUtils.remove(ds, 'up');
            }
            
            if( (x+17) > this.map.widthInPixels ){
                ArrUtils.remove(ds, 'right');
            }
            if( (y+17) > this.map.heightInPixels){
                ArrUtils.remove(ds, 'down');
            }
            
            let tile :Phaser.Tilemaps.Tile = null;

            if( (tile = this.map.getTileAtWorldXY(x-1, y, false, this.cameras.main, this.layer)) && tile.index <4 ){
                ArrUtils.remove(ds, 'left');
            }
            if( (tile = this.map.getTileAtWorldXY(x+17, y, false, this.cameras.main, this.layer)) && tile.index <4){
                ArrUtils.remove(ds, 'right');    
            }
            if( (tile = this.map.getTileAtWorldXY(x, y-1, false, this.cameras.main, this.layer)) && tile.index <4){
                ArrUtils.remove(ds, 'up');
            }
            if( (tile = this.map.getTileAtWorldXY(x, y+17, false, this.cameras.main, this.layer)) && tile.index <4){
                ArrUtils.remove(ds, 'down');
            }
            
            this.enemies.getChildren().forEach( (other: any) => {
                const tankInfo = enemy.getData('tankInfo');
                
                if(!tankInfo || !tankInfo.dir || ds.length===1){ return; }
                
                if(enemy !== other){
                    let {x: x1, y: y1} = enemy;
                    let {x: x2, y: y2} = other;
                    
                    let dx = x2 - x1;
                    let dy = y2 - y1;
                    let dd = Math.sqrt(dx*dx+dy*dy);

                    if(dd < 8){
                        ArrUtils.remove(ds, tankInfo.dir);
                    }
                }
            });
            
            let animName = '', go = 0;
            if(ds.length === 1){
                animName = ds[go];
            } else {
                // @ts-ignore
                go = parseInt(Math.random() * ((ds.length<<1)-1));
                go = go > (ds.length-1) ? go-(ds.length-1) : go;
                animName = ds[go];
            }
            enemy.play(animName, true);

            const tankInfo = enemy.getData('tankInfo');
            tankInfo.dir = animName;
            
            // enemy.play(animName, true);
            let n = go & 1; let enemySpeed = this.speed;
            if( n > 0){
                enemySpeed = enemySpeed + Math.floor(Math.random() * 5);
            } else {
                enemySpeed = enemySpeed - Math.floor(Math.random() * 5);
            }
            if( ['left', 'up'].indexOf(animName) !== -1){
                enemySpeed = -enemySpeed;
            }
            
            console.log('see go, animName and speed(' + go + ',' + animName + ',' + enemySpeed + ')');
            
            if( ['up','down'].indexOf(animName) !== -1){
                enemy.body.setVelocityY(enemySpeed);
            } else {
                enemy.body.setVelocityX(enemySpeed);
            }
        });
    }

    private initEnemy(i: number): void {
        //@ts-ignore
        let imgId = parseInt(i/4) * 32 + (i % 4)*2;
        const enemy = this.enemies.create( 0, 0, 'enemy', imgId )
                .setOrigin(0, 0)
                ;
        let tinit = i % 4;
        enemy.setPosition(enemyData.positions[tinit][0], enemyData.positions[tinit][1]);
        
        enemy.setData('tankInfo', {tinit: tinit});
        
        this.add.existing(enemy);
        this.physics.world.enable(enemy);
        enemy.body.setCollideWorldBounds(true, 0, 0);

        enemy.anims.create({
            key: 'up',
            frames:[
                {key: 'enemy', frame: imgId},
                {key: 'enemy', frame: imgId+1}
            ],
            frameRate: 5,
            repeat: -1
        });

        enemy.anims.create({
            key: 'right',
            frames:[
                {key: 'enemy', frame: imgId+8},
                {key: 'enemy', frame: imgId+9},
            ],
            frameRate: 5,
            repeat: -1
        });

        enemy.anims.create({
            key: 'down',
            frames:[
                {key: 'enemy',  frame: imgId+16},
                {key: 'enemy',  frame: imgId+17}
            ]
        });

        enemy.anims.create({
            key: 'left',
            frames:[
                {key: 'enemy',  frame: imgId+24},
                {key: 'enemy',  frame: imgId+25}
            ],
            framesRate: 5, 
            repeat: -1
        });
    }
    private initPlayerAnimations(): void {
        this.player.anims.create({
            key: 'up',
            frames:[
                {key: 'tank', frame: 0},
                {key: 'tank', frame: 1}
            ],
            frameRate: 5,
            repeat: -1
        });

        this.player.anims.create({
            key: 'right',
            frames:[
                {key: 'tank', frame: 8},
                {key: 'tank', frame: 9}
            ],
            frameRate: 5,
            repeat: -1
        });

        this.player.anims.create({
            key: 'down',
            frames:[
                {key: 'tank', frame: 16},
                {key: 'tank', frame: 17}
            ],
            frameRate: 5,
            repeat: -1
        });

        this.player.anims.create({
            key: 'left',
            frames:[
                {key: 'tank', frame: 24},
                {key: 'tank', frame: 25}
            ],
            frameRate: 5, 
            repeat: -1
        });
    }
    
    layerBoundsCheckWithPlayer(){
        const entity = this.player;
        if(entity.x < entity.width/2){
            entity.x = entity.width/2;
        }

        if(entity.x > (this.map.widthInPixels - entity.width/2)){
            entity.x = (this.map.widthInPixels - entity.width/2);
        }

        if(entity.y < entity.height/2){
            entity.y = entity.height/2
        }

        if(entity.y > (this.map.heightInPixels - entity.height/2)){
            entity.y = (this.map.heightInPixels - entity.height/2)
        }
    }
}